#include <windows.h>
#include "d3d11render.h"


LONG		gScreenWidth = 1024;
LONG		gScreenHeight = 768;

HINSTANCE	ghInstance;
HWND		ghWnd;

dh_renderer*		gpRenderer = NULL;

int			gVertexBuffer;
int			gIndexBuffer;
int			gVertexFormat;
int			gShaderHandle;


static void DestroyWindow()
{
	DestroyWindow( ghWnd );
	ghWnd = NULL;
	ghInstance = NULL;
}



static LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch( uMsg )
	{
		case WM_QUIT:
		{
			PostQuitMessage( 0 );
			DestroyWindow();
		}
		
		case WM_CLOSE:
		{
			PostQuitMessage( 0 );
			return 0;
		}
		
		default:
		{
			return DefWindowProc( hWnd, uMsg, wParam, lParam );
			break;
		}
	}
	
	return DefWindowProc( hWnd, uMsg, wParam, lParam );
}



static bool DHCreateWindow( const char* windowName )
{
	WNDCLASS wc;
	DWORD	 dwExStyle;
	DWORD	 dwStyle;
	RECT	 windowRect;
	
	windowRect.left = 0;
	windowRect.right = gScreenWidth;
	windowRect.top = 0;
	windowRect.bottom = gScreenHeight;
	
	ghInstance = GetModuleHandle( NULL );
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = (WNDPROC)WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = ghInstance;
	wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "D3D11TESELLATE";
	
	if( !RegisterClass( &wc ) )
		return false;
		
	dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
	dwStyle   = WS_OVERLAPPEDWINDOW;
	
	AdjustWindowRectEx( &windowRect, dwStyle, FALSE, dwExStyle );
	
	if( !( ghWnd = CreateWindowEx( dwExStyle, "D3D11TESELLATE", windowName, dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
								   0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, ghInstance, NULL ) ) ) 
	{
		DestroyWindow();
		return false;
	}
	
	ShowWindow( ghWnd, SW_SHOW );
	SetForegroundWindow( ghWnd );
	SetFocus( ghWnd );
	
	return true;
}


static bool CreateDevice()
{
	dh_render_init init;
	init.displayWidth		= gScreenWidth;
	init.displayHeight		= gScreenHeight;
	init.refreshRate		= 60;
	init.windowed			= true;
	init.window				= ghWnd;
	init.depthBits			= 24;
	init.stencilBits		= 8;
	
	if( !gpRenderer->InitializeRenderer( init ) )
		return false;
	

	// Create an effect //
//	dh_effect_desc desc;
//	desc.srcFile		= "Media/Effects/effect_test.fx";
//	desc.macroNames		= NULL;
//	desc.macroDefs		= NULL;
//	desc.nMacros		= 0;
//	desc.entryPoint		= "";
//	desc.effectProfile  = "fx_5_0";
//	gShaderHandle = gpRenderer->CreateEffect( desc );
	long fileLen;
	FILE* f;
	char* shaderCode;

	f = fopen("Media/Effects/test.vert", "r");
	if(!f)
		return -1;

	fseek(f, 0, SEEK_END);
	fileLen = ftell(f);
	fseek(f, 0, SEEK_SET);
	shaderCode = new char[fileLen];
	fread(shaderCode, 1, fileLen, f);
	fclose(f);
	gShaderHandle = gpRenderer->CreateVertexShader(shaderCode);
	delete[] shaderCode;

	// Create Vertex buffer //
	dh_colored_vertex		verts[3];
	verts[0].pos = dh_vec3f( -0.5F, 0.0F, 1.0F );
	verts[1].pos = dh_vec3f( 0.0F, 1.0F, 1.0F );
	verts[2].pos = dh_vec3f( 0.5F, 0.0F, 1.0F );
	verts[0].color = MAKE_ARGB( 255, 255, 0, 0 );
	verts[1].color = MAKE_ARGB( 255, 255, 0, 0 );
	verts[2].color = MAKE_ARGB( 255, 255, 0, 0 );

	gVertexBuffer = gpRenderer->CreateVertexBuffer( verts, sizeof( dh_colored_vertex ) * 3, USAGE_STATIC );

	// Create Index Buffer //
	unsigned int indices[3];
	indices[0] = 0;
	indices[1] = 2;
	indices[2] = 1;

	gIndexBuffer = gpRenderer->CreateIndexBuffer( indices, 3, USAGE_STATIC );

	// Create Vertex format //
	dh_vertex_element vDecl[2];
	vDecl[0].shaderHandle = gShaderHandle;
	vDecl[0].techniqueName = "depthpass";
	vDecl[0].techniquePass = 0;
	vDecl[0].semantic = "POSITION";
	vDecl[0].semanticIndex = 0;
	vDecl[0].format = FORMAT_RGB32_FLOAT;
	vDecl[0].inputSlot = 0;
	vDecl[0].alignmentBytes = 0;
	vDecl[0].inputClassType = VERTEX_DATA;
	vDecl[0].nInstances = 0;

	vDecl[1].shaderHandle = gShaderHandle;
	vDecl[1].techniqueName = "depthpass";
	vDecl[1].techniquePass = 0;
	vDecl[1].semantic = "COLOR";
	vDecl[1].semanticIndex = 0;
	vDecl[1].format = FORMAT_RGBA8_UINT;
	vDecl[1].inputSlot = 0;
	vDecl[1].alignmentBytes = 12;
	vDecl[1].inputClassType = VERTEX_DATA;
	vDecl[1].nInstances = 0;

	gVertexFormat = gpRenderer->CreateVertexFormat( vDecl, 2 );
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	gpRenderer = new dh_renderer;

	bool done = false;
	MSG  message;
	
	if( !DHCreateWindow( "Testing D3D11" ) )
	{
		DestroyWindow();
		return 0;
	}
		
	if( !CreateDevice() )
	{
		delete gpRenderer;
		DestroyWindow();
		return 0;
	}
	
	while( !done )
	{
		if( PeekMessage( &message, NULL, 0, 0, PM_REMOVE ) ) 
		{
			if( message.message == WM_QUIT )
				done = true;
			
			else
			{
				TranslateMessage( &message );
				DispatchMessage( &message );
			}
		}
		
		else
		{
			gpRenderer->ClearBackBuffer( CLEAR_BACKBUFFER, 0.0F, 0.0F, 0.0F );
			gpRenderer->ClearDepthStencilBuffer( CLEAR_ZBUFFER | CLEAR_STENCILBUFFER, 1.0, 0x00 );

			gpRenderer->PresentScene();
		}
	}
	
	DestroyWindow();
	return ( (INT)message.wParam );
}